////////////////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////////////////

// Header
#include "ANNPluginInterface.hpp"

// Wildcard
#include "SCProgram.hpp"

// Types
#include "VFloat.hpp"

// Conversion functions
#include "Convert.hpp"

// Streams
#include <iostream>
#include <sstream>

// Math
#include <cmath>

// Macros
#include "ANNMacros.hpp"

// Exceptions
#include "AssertionException.hpp"

////////////////////////////////////////////////////////////////////////////////
// Implementation
////////////////////////////////////////////////////////////////////////////////

using namespace std;
using namespace Types;
using namespace Toolkit;
using namespace Exceptions;
using namespace SC;


void ANNPluginInterface::Evaluate(
	SCSystem & universe,
	const vector<string> & sample,
	const bool update
) {
#ifdef PLUGIN_DEBUG
	cout << "Evaluate new sample" << endl;
#endif
	// Sets the input
	universe.ReplaceSchema1(UIntToBStr(sample.size(), INTEGER_SIZE), UN_S1_INPUT_SIZE_IDX, INTEGER_SIZE);
	VFloat vFloat(IS_SIGNED, INT_P_SIZE, DEC_P_SIZE);
	for (unsigned int i=0; i<sample.size(); ++i) {
		stringstream ss;
		ss << sample[i];
		float data;
		ss >> data;
		vFloat.SetStringFromFloat(data);
		universe.ReplaceSchema1(vFloat.GetStringValue(), UN_S1_INPUT_IDX + (i * FLOAT_SIZE), FLOAT_SIZE);
	}
	// Disables supervision
	universe.ReplaceKernel(C_FALSE, UN_K_SUPERVISION_FLAG_IDX, 1);
	// Set the update flag if required
	universe.ReplaceKernel((update?C_TRUE:C_FALSE), UN_K_UPDATE_FLAG_IDX, 1);
}

void ANNPluginInterface::Learn(
	SCSystem & universe,
	const vector<double> & expected
) {
#ifdef PLUGIN_DEBUG
	cout << "Learn new sample (supervision of size " << expected.size() << ")" << endl;
#endif
	// Enables supervision
	universe.ReplaceKernel(C_TRUE, UN_K_SUPERVISION_FLAG_IDX, 1);
	// Sets the expected results
	universe.ReplaceKernel(UIntToBStr(expected.size(), INTEGER_SIZE), UN_K_EXPECTED_SIZE_IDX, INTEGER_SIZE);
	VFloat vFloat(IS_SIGNED, INT_P_SIZE, DEC_P_SIZE);
	for (unsigned int i=0; i<expected.size(); ++i) {
		vFloat.SetStringFromFloat(expected[i]);
		universe.ReplaceKernel(vFloat.GetStringValue(), UN_K_EXPECTED_IDX + (i * FLOAT_SIZE), FLOAT_SIZE);
	}
}

const vector<double> ANNPluginInterface::GetOutput(const SCSystem & universe) {
#ifdef PLUGIN_DEBUG
	//cout << "Collect output" << endl;
#endif
	vector<double> result;
	int nb_outputs = BStrToUInt(universe.GetSchema2(UN_S2_OUTPUT_SIZE_IDX, INTEGER_SIZE));
	VFloat resultF(IS_SIGNED, INT_P_SIZE, DEC_P_SIZE);
	for (int d=0; d<nb_outputs; ++d) {
		resultF.StringValue() = universe.GetSchema2(UN_S2_OUTPUT_IDX + (d * FLOAT_SIZE), FLOAT_SIZE);
		result.push_back(resultF.GetFloatValue());
	}
	return result;
}

////////////////////////////////////////////////////////////////////////////////
